
#ifndef _TTG_PIPELINE_INTERNAL_BINDING_
#define _TTG_PIPELINE_INTERNAL_BINDING_
#include "Common/Definitions.h"

#include <vector>

#include "Runtime.Low/Devices.h"
#include "Runtime.Low/Pipeline/Nodes/ProcessorNode.h"

namespace ttg_internal
{
	namespace pipeline
	{
		//Base class for any bindings.
		template <class ProcessInType, class ProcessOutType,
				  class InType, class OutType>
		class Binding :public ttg_internal::pipeline::IDataProcessor<InType>
		{
			private:
				ttg::devices::LogicalDevice target_device;
				ttg_internal::pipeline::ProcessorNode<ProcessInType, ProcessOutType,
													  InType, OutType> *owner;
			protected:
				//Sends data to next nodes.
				inline void sendNext(ProcessOutType data)
				{ owner->sendNext(data); }
				//Sends data to next nodes.
				inline void sendNext(std::list<ProcessOutType> &data)
				{ owner->sendNext(data); }
				//Sends data to next nodes.
				inline void sendNext(std::vector<ProcessOutType> &data)
				{ owner->sendNext(data); }
				//Sends data to next nodes.
				inline void sendNext(ttg::structures::Enumerator<ProcessOutType> &data)
				{ owner->sendNext(data); }
				//Sends data to this node.
				inline void sendThis(InType data)
				{ owner->sendThis(data); }
				//Sends data to this node.
				inline void sendThis(std::list<InType> &data)
				{ owner->sendThis(data); }
				//Sends data to this node.
				inline void sendThis(std::vector<InType> &data)
				{ owner->sendThis(data); }
				//Sends data to this node.
				inline void sendThis(ttg::structures::Enumerator<InType> &data)
				{ owner->sendThis(data); }
			public:
				//Creates binding to target device.
				inline Binding(ttg::devices::LogicalDevice target_device)
				{ this->target_device = target_device; }
				//Returns type of target device.
				inline ttg::devices::LogicalDevice getTargetDevice()
				{ return target_device; }
				//IDataProcessor<InType> member. Applies changes. Will be called after "process()".
				//Note: ID is ID of current context.
				virtual void startProcessing(ttg::pipeline::ContextID ID)
				{ owner->startProcessing(ID); }
				//IDataProcessor<InType> member. Applies changes. Will be called after "process()".
				//Note: ID is ID of current context.
				virtual void finishProcessing(ttg::pipeline::ContextID ID)
				{ owner->finishProcessing(ID); }
				//Notifies about start of processing.
				virtual void onBegin(ttg::pipeline::ContextID ID)
				{ /*nothing*/ }
				//IDataProcessor<InType> member. Processes data.
				virtual void process(ttg::pipeline::ContextID ID, ProcessInType data) = 0;
				//Notifies about end of processing.
				virtual void onEnd(ttg::pipeline::ContextID ID)
				{ /*nothing*/ }
				//IDataProcessor<InType> member. Returns abstract difficulty of data.
				//If returned value is lesser that 0, than processing is unavailable.
				virtual double getDifficulty(ProcessInType data)
				{ return 1.0; }
				//Interal member, that should be hidden. Do not use it directly!
				//Note: it sets owner, that will receive output data.
				void setOwner(ttg_internal::pipeline::ProcessorNode<ProcessInType, ProcessOutType,
																	InType, OutType> *owner)
				{ this->owner = owner; }
				//Internal method, provides access to binding's owner. Do not use it directly!
				inline ttg_internal::pipeline::ProcessorNode<ProcessInType, ProcessOutType,
															 InType, OutType> *getOwner()
				{ return owner; }
		};
	}
}

#endif
